import React from "react";
import { makeStyles } from "@material-ui/core/styles";
import { Link } from "react-router-dom";
import Breadcrumbs from '@material-ui/core/Breadcrumbs';
import Typography from '@material-ui/core/Typography';
import Divider from '@material-ui/core/Divider';
import Skeleton from '@material-ui/lab/Skeleton';
import AllOutIcon from '@material-ui/icons/AllOut';
import Box from '@material-ui/core/Box';

// core components
import Button from "components/CustomButtons/Button.js";
import Card from "components/Card/Card.js";
import CardHeader from "components/Card/CardHeader.js";
import CardBody from "components/Card/CardBody.js";
import GridItem from "components/Grid/GridItem.js";
import GridContainer from "components/Grid/GridContainer.js";
import LineChart from "views/Dashboard/LineChart.js";
import StackedBarChart from "views/Dashboard/StackedBarChart.js";
import MultiBarChart from "views/Dashboard/MultiBarChart.js";
import SeriesLabels from "views/Dashboard/SeriesLabels.js";
import dashboardStyles from "assets/jss/material-dashboard-react/views/dashboardStyle.js";
import fontStyles from "assets/jss/material-dashboard-react/components/typographyStyle.js";

import { getLoggedSession, redirectToLogin, truncateToRadix } from 'utils.js';
import { getAllComputePoolStatus } from "nano_api.js";

import {
  primaryColor,
  infoColor,
  successColor,
  warningColor,
  grayColor,
  whiteColor,
  roseColor,
} from "assets/jss/material-dashboard-react.js";

const i18n = {
  'en':{
    viewButton: "View Cell Status",
    zone: "Zone Status",
    title: 'Compute Pool',
    pools: 'All Compute Pools',
    cells: 'Compute Cells',
    instances: 'Instances',
    disks: 'Storage(GB)',
    memory: 'Memory',
    ioUsage: 'IO Usage',
    enabled: 'Enabled',
    disabled: 'Disabled',
    online: 'Online ',
    offline: 'Offline ',
    stopped: 'Stopped ',
    running: 'Running ',
    lost: 'Lost ',
    migrate: 'Migrating ',
    used: 'Used ',
    available: 'Available ',
    coresUsed: 'Cores Used',
    throughput: 'Throughput',
    receive: 'Receive ',
    send: 'Send ',
    write: 'Write ',
    read: 'Read ',
  },
  'cn':{
    viewButton: "查看节点状态",
    zone: "全域状态",
    title: '计算资源池',
    pools: '所有计算资源池',
    cells: '资源节点',
    instances: '云主机实例',
    disks: '磁盘空间(GB)',
    memory: '内存',
    ioUsage: 'IO吞吐量',
    enabled: '启用',
    disabled: '禁用',
    online: '在线',
    offline: '离线',
    stopped: '停止',
    running: '运行',
    lost: '失联',
    migrate: '迁移中',
    used: '已用',
    available: '可用',
    coresUsed: '核心已占用',
    throughput: '吞吐量',
    receive: '接收',
    send: '发送',
    write: '写入',
    read: '读取',
  }
}

const seriesColor1 = infoColor[0];
const seriesColor2 = successColor[0];
const seriesColor3 = warningColor[0];
const seriesColor4 = primaryColor[0];
const disabledColor = grayColor[2];

const shadowChartPanel = {
  borderRadius: "3px",
  marginTop: "-20px",
  // marginLeft: "10px",
  // marginRight: "10px",
  padding: "15px",
};

const styles = {
  ...fontStyles,
  ...dashboardStyles,
  cardWithDivider: {
    borderTop: "1px solid " + grayColor[10],
  },
  coresChart: {
    ...shadowChartPanel,
    background: successColor[0],
  },
  memoryChart: {
    ...shadowChartPanel,
    background: infoColor[0],
  },
  networkChart: {
    ...shadowChartPanel,
    background: warningColor[0],
  },
  diskChart: {
    ...shadowChartPanel,
    background: roseColor[0],
  },
}

const useStyles = makeStyles(styles);

const SinglePoolStatus = props => {
  const { lang, status, poolName } = props;
  const classes = useStyles();
  const texts = i18n[lang];
  const title = texts.title + ': ' + poolName;
  const GiB = 1 << 30;
  const MiB = 1 << 20;
  const [ offlineCell, onlineCell ] = status.cells;
  const cellData = [{
    value: offlineCell,
    label: texts.offline,
    color: disabledColor,
  },{
    value: onlineCell,
    label: texts.online,
    color: seriesColor2,
  }];
  const cellsLabel = <SeriesLabels key="cells-labels" title={texts.cells} series={cellData} valueName='value' colorName='color' labelName='label' baseClass={dashboardStyles.cardCategory}/>;

  const [ stoppedInstance, runningInstance, lostInstance, migrateInstance ] = status.instances;
  const instanceData = [{
    value: stoppedInstance,
    label: texts.stopped,
    color: disabledColor,
  },{
    value: runningInstance,
    label: texts.running,
    color: seriesColor1,
  },{
    value: lostInstance,
    label: texts.lost,
    color: seriesColor3,
  },{
    value: migrateInstance,
    label: texts.migrate,
    color: seriesColor4,
  }];
  const instancesLabel = <SeriesLabels key="instances-labels" title={texts.instances} series={instanceData} valueName='value' colorName='color' labelName='label' baseClass={dashboardStyles.cardCategory}/>;

  const availableDisk = truncateToRadix(status.available_disk / GiB, 2);
  const usedDisk = truncateToRadix((status.max_disk - status.available_disk) /GiB, 2);
  const storageData = [{
    value: availableDisk,
    label: texts.available,
    color: seriesColor1,
  },{
    value: usedDisk,
    label: texts.used,
    color: seriesColor4,
  }];
  const storageLabel = <SeriesLabels key="storage-labels" title={texts.disks} series={storageData} valueName='value' colorName='color' labelName='label' baseClass={dashboardStyles.cardCategory}/>;
  //core usage
  var usedCores = {
    label: texts.coresUsed,
    color: whiteColor,
    data: [],
  }

  var maxCores = 0;
  status.coreRecords.forEach( data =>{
    usedCores.data.push(data.current);
    maxCores = Math.max(maxCores, data.max);
  })

  const coresChart = (
    <GridItem xs={12} sm={6} md={3} key='cores-usage'>
      <Box m={0} p={0} className={classes.coresChart} boxShadow={2}>
        <LineChart
          series={[usedCores]}
          minTickStep={1}
          maxValue={maxCores}
          />
      </Box>
    </GridItem>
  )
  //memory
  var usedMemory = {
    label: texts.used + texts.memory,
    color: grayColor[4],
    data: [],
  };
  var availableMemory = {
    label: texts.available + texts.memory,
    color: successColor[1],
    data: [],
  };
  status.memoryRecords.forEach( data =>{
    usedMemory.data.push(data.used);
    availableMemory.data.push(data.available)
  })
  const memoryChart = (
    <GridItem xs={12} sm={6} md={3} key='memory-usage'>
      <Box m={0} p={0} className={classes.memoryChart} boxShadow={2}>
        <StackedBarChart
          series={[usedMemory, availableMemory]}
          minTickStep={1 << 10}
          displayValue={ mib => {
            const GiB = 1 << 10;
            if (0 === mib){
              return '0';
            }else if (mib >= GiB){
              if (0 === mib % GiB){
                return (mib / GiB).toString() + ' GB';
              }else{
                return (mib / GiB).toFixed(2) + ' GB';
              }
            }else {
              return mib.toString() + ' MB';
            }
          }}
          />
      </Box>
    </GridItem>
  )
  //network
  var networkReceive = {
    label: texts.receive + texts.throughput,
    color: infoColor[3],
    data: [],
  };
  var networkSend = {
    label: texts.send + texts.throughput,
    color: primaryColor[1],
    data: [],
  };
  status.networkRecords.forEach( data =>{
    networkReceive.data.push(truncateToRadix(data.receive/ MiB, 2) );
    networkSend.data.push(truncateToRadix(data.send/ MiB, 2));
  })
  const displaySpeedByMB = speed => {
    const gb = 1 << 10;
    if (speed >= gb){
      if (0 === speed % gb){
        return (speed / gb).toString() + ' GB/s';
      }else{
        return (speed / gb).toFixed(2) + ' GB/s';
      }
    }else{
      if (Number.isInteger(speed)){
        return speed.toString() + ' MB/s';
      }else{
        return speed.toFixed(2) + ' MB/s';
      }
    }
  }
  const networkSeries = [ networkReceive, networkSend ];
  const networkChart = (
    <GridItem xs={12} sm={6} md={3} key='network-usage'>
      <Box m={0} p={0} className={classes.networkChart} boxShadow={2}>
        <MultiBarChart
          series={networkSeries}
          displayValue={displaySpeedByMB}
          minTickStep={1}
          />
      </Box>
    </GridItem>
  )
  //disk IO
  var diskWrite = {
    label: texts.write + texts.throughput,
    color: successColor[1],
    data: [],
  };
  var diskRead = {
    label: texts.read + texts.throughput,
    color: infoColor[3],
    data: [],
  };
  status.diskRecords.forEach( data =>{
    diskWrite.data.push(truncateToRadix(data.write / MiB, 2));
    diskRead.data.push(truncateToRadix(data.read / MiB, 2));
  })
  const diskSeries = [ diskWrite, diskRead ];
  const diskIOChart = (
    <GridItem xs={12} sm={6} md={3} key='io-usage'>
      <Box m={0} p={0} className={classes.diskChart} boxShadow={2}>
        <MultiBarChart
          series={diskSeries}
          displayValue={displaySpeedByMB}
          minTickStep={1}
          />
      </Box>
    </GridItem>
  )
  const content = [
    coresChart,
    memoryChart,
    networkChart,
    diskIOChart,
  ];
  const dataLabels = [
    cellsLabel,
    instancesLabel,
    storageLabel,
  ];
  return (
    <Card chart>
      <CardHeader>
      <GridContainer>
        {content}
      </GridContainer>
      </CardHeader>
      <CardBody>
        <Typography component='span' className={classes.cardTitle}>
          {title}
        </Typography>
        {dataLabels}
        <Box m={0} p={2} className={classes.cardWithDivider}>
          <GridContainer>
            <GridItem xs={6} sm={4} md={3}>
              <Link to={'/admin/dashboard/pools/' + poolName}>
                <Button size="sm" color="info" round><AllOutIcon />{texts.viewButton}</Button>
              </Link>
            </GridItem>
          </GridContainer>
        </Box>
      </CardBody>
    </Card>
  )
}

export default function PoolStatus(props) {
  const CoreArraySize = 5;
  const MemoryArraySize = 5;
  const NetworkIOArraySize = 5;
  const DiskIOArraySize = 5;
  const [ allStatus, setAllStatus ] = React.useState(null);
  const texts = i18n[props.lang];

  React.useEffect(() =>{
    var mounted = true
    var statusMap = new Map();

    const queryPoolsStatus = () =>{
      const MiB = 1 << 20;
      const onOperateSuccess = dataList => {
        dataList.forEach(status =>{
          const poolName = status.name;
          let coreRecords, memoryRecords, networkRecords, diskRecords;
          if(!statusMap.has(poolName)){
            //append & update for exists
            coreRecords = new Array(CoreArraySize - 1).fill({
              current: 0,
              max: 0,
            });
            memoryRecords = new Array(MemoryArraySize - 1).fill({
              available: 0,
              used: 0,
            });
            networkRecords = new Array(NetworkIOArraySize - 1).fill({
              receive: 0,
              send: 0,
            });
            diskRecords = new Array(DiskIOArraySize - 1).fill({
              write: 0,
              read: 0,
            });
          }else{
            //new pool
            const current = statusMap.get(poolName);
            coreRecords = current.coreRecords;
            coreRecords.shift();
            memoryRecords = current.memoryRecords;
            memoryRecords.shift();
            networkRecords = current.networkRecords;
            networkRecords.shift();
            diskRecords = current.diskRecords;
            diskRecords.shift();
          }
          coreRecords.push({
            current: truncateToRadix(status.cpu_usage, 2),
            max: status.max_cpu,
          });
          memoryRecords.push({
            available: truncateToRadix(status.available_memory/MiB, 2),
            used: truncateToRadix((status.max_memory - status.available_memory)/MiB, 2),
          });
          networkRecords.push({
            receive: status.receive_speed,
            send: status.send_speed,
            // receive: 100 * MiB * Math.random(),
            // send: 100 * MiB * Math.random(),
          });
          diskRecords.push({
            write: status.write_speed,
            read: status.read_speed,
            // write: 10 * MiB * Math.random(),
            // read: 10 * MiB * Math.random(),
          });

          const updated = {
            ...status,
            coreRecords: coreRecords,
            memoryRecords: memoryRecords,
            networkRecords: networkRecords,
            diskRecords: diskRecords,
          };
          statusMap.set(poolName, updated);
        });
        var newStatus = new Map();
        statusMap.forEach((value, key) =>{
          newStatus.set(key, value);
        })
        setAllStatus(newStatus);
      }
      getAllComputePoolStatus(onOperateSuccess);
    }

    queryPoolsStatus();
    const updateInterval = 2 * 1000;
    var timerID = setInterval(()=>{
      if (mounted){
        queryPoolsStatus();
      }
    }, updateInterval);
    return () =>{
      mounted = false;
      clearInterval(timerID);
    }
  }, []);

  //reder begin
  var session = getLoggedSession();
  if (null === session){
    return redirectToLogin();
  }

  let content;
  if (!allStatus){
    content = <Skeleton variant="rect" style={{height: '10rem'}}/>;
  }else{
    var nameList = [];
    allStatus.forEach( (value, key) =>{
      nameList.push(key);
    });
    nameList.sort();
    content = [];
    nameList.forEach(poolName =>{
      var status = allStatus.get(poolName);
      content.push(
        <GridItem xs={12} key={poolName}>
          <SinglePoolStatus status={status} lang={props.lang} poolName={poolName}/>
        </GridItem>
      );
    });

  }

  const breadcrumbs = [
    <Link to='/admin/dashboard/' key={texts.zone}>{texts.zone}</Link>,
    <Typography color="textPrimary" key={texts.pools}>{texts.pools}</Typography>,
  ];

  return (
      <GridContainer>
        <GridItem xs={12}>
        <Breadcrumbs separator="›" aria-label="breadcrumb">
          {breadcrumbs}
        </Breadcrumbs>
        </GridItem>
        <GridItem xs={12}>
          <Box mt={3} mb={3}>
            <Divider/>
          </Box>
        </GridItem>
        {content}
      </GridContainer>
  )
}
